package com.op.util;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.op.constants.FileUploadConstant;
import com.op.core.entity.File;
import com.op.core.service.FileService;
import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import io.minio.errors.MinioException;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * 向minio服务器上传文件工具类
 * ClassName： FileUtil
 * Date： 2021/10/7 8:58
 *
 * @author 孤焰
 * @version 1.0
 **/

@Getter
@Component
//@PropertySource(value = "classpath:minio.yml")
@ConfigurationProperties(prefix = "file.minio")
@Slf4j
public class FileUtil {
    /**
     * 图片服务器baseUrl
     */
    private static String url;
    /**
     * 图片服务器用户名
     */
    private static String username;
    /**
     * 图片服务器密码
     */
    private static String password;
    /**
     * 用于操作数据库
     */
    @Resource
    private FileService fileService;

    private static FileUtil fileUtil;

    @PostConstruct
    public void init() {
        fileUtil = this;
    }

    /**
     * 上传图片
     * @param file 图片文件
     * @return 图片路径
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws MinioException
     */
    public static String uploadImg(MultipartFile file) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
        return upload(file, FileUploadConstant.IMG_BUCKET);
    }

    /**
     * 上传文件
     * @param file 文件实体
     * @param bucket 所在的服务器桶
     * @return 文件路径
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws MinioException
     */
    public static String upload(MultipartFile file, String bucket) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
        // 文件io流md5形式
        String md5 = DigestUtils.md2Hex(file.getInputStream());
        // 文件大小
        Long size = file.getSize();
        // 文件后缀名
        String suffix = "." + FilenameUtils.getExtension(file.getOriginalFilename());
        // 文件服务器中的文件名
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern(FileUploadConstant.FORMAT_DATE_TIME)));
        stringBuilder.append(UUID.randomUUID().toString().substring(0, 23).replaceAll("-", ""));
        stringBuilder.append(suffix);
        String path = stringBuilder.toString();
        File fileDb = fileUtil.fileService.getOne(new QueryWrapper<>(new File(bucket, md5, size, suffix)));
        // 判断图片服务器中是否已经上传了此图片
        if (fileDb != null) {
            return fileDb.getPath();
        }
        // 使用MinIO服务的URL，端口，Access key和Secret key创建一个MinioClient对象
        MinioClient minioClient = new MinioClient(url, username, password);
        // 检查存储桶是否已经存在
        boolean isExist = minioClient.bucketExists(bucket);
        if(isExist) {
            log.info("该存储桶已存在");
        } else {
            // 创建一个名为xxx的存储桶。
            minioClient.makeBucket(bucket);
        }
        PutObjectOptions options = new PutObjectOptions(size, 0);
        options.setContentType(file.getContentType());
        // 使用putObject上传一个文件到存储桶中。
        minioClient.putObject(bucket,stringBuilder.toString(), file.getInputStream(), options);
        log.info("{}文件已成功上转至{}桶中", stringBuilder.toString(), bucket);
        fileDb = new File(bucket, path, md5, size, suffix);
        fileUtil.fileService.save(fileDb);
        log.info("file数据已成功添加至数据库中, file:{}", fileDb);

        return stringBuilder.toString();
    }

    /**
     * @param url 文件服务器的基础url
     */
    @Value("${file.minio.url}")
    public void setUrl(String url) {
        FileUtil.url = url;
    }

    /**
     * @param username 登录文件服务器的用户名
     */
    @Value("${file.minio.username}")
    public void setUsername(String username) {
        FileUtil.username = username;
    }

    /**
     * @param password 登录文件服务器的密码
     */
    @Value("${file.minio.password}")
    public void setPassword(String password) {
        FileUtil.password = password;
    }
}
